abstract class Equable<T> {
  T get compareField;

  @override
  bool operator ==(Object other) {
    return runtimeType == other.runtimeType &&
        other is Equable &&
        compareField == other.compareField;
  }

  @override
  int get hashCode => compareField.hashCode;
}

abstract class EquableMulti {
  List get compareFields;

  @override
  bool operator ==(Object other) {
    return runtimeType == other.runtimeType &&
        other is EquableMulti &&
        compareList(compareFields, other.compareFields);
  }

  static bool compareList(List a, List b) {
    if (a.length != b.length) return false;
    for (int i = 0; i < a.length; i++) {
      if (a[i] != b[i]) {
        return false;
      }
    }
    return true;
  }

  static int listHashCode(List a) {
    int hashCode = 0;
    for (var item in a) {
      hashCode ^= item.hashCode;
    }
    return hashCode;
  }

  @override
  int get hashCode => listHashCode(compareFields);
}
